package sv;

import java.awt.Color;

public class ToolBox {

	static boolean[][][] matrix1 = new boolean[9][9][9];
	static boolean[][][] matrix2 = new boolean[9][9][9];
	static boolean[][][] matrix3 = new boolean[9][9][9];

	static int[][][] input = new int[3][][];

	static boolean[] end = new boolean[]{false,false,false};
	
	static long[] passi = new long[3];
	static int[] min = new int[]{Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE};
	static long[] max = new long[3];
	
	private static int rit=0;
	private static Object wait=new Object();
	
	static GraphicsWhindow gWindow;

	/**
	 * Costruttore di default che non imposta la matrice
	 */
	public ToolBox() {
		// TODO
	}

	/**
	 * Costruttore iniziale che inizializza la matrice con la linearizzazione
	 * presente in linearMatrix
	 * 
	 * @param linearMatrix
	 *            : array contenente la linearizzazione della matrice, lo
	 *            <b>0</b> indica che il valore non e' stato impostato
	 */
	public ToolBox(int[][] inputMatrix,boolean test) {
		inizializzazione(inputMatrix,3);
		if(test)
			gWindow = new GraphicsWhindow();
		// stampaCose();
	}
	
	public void inizializzazione(int[][] inputMatrix,int nS){
		if(nS==3){
			for(int i=0;i<input.length;i++)
				input[i]=inputMatrix;
		}
		else
			input[nS] = inputMatrix;
		
		if (inputMatrix.length != 9) // controlla che il n dei valori inseriti
										// sia corretto
			throw new IllegalArgumentException("la matrice non e' corretta");
		else
			for (int i = 0; i < 9; i++)
				if (inputMatrix[i].length != 9)
					throw new IllegalArgumentException(
							"la matrice non e' corretta");

		for (int r = 0; r < 9; r++) {
			for (int c = 0; c < 9; c++) {
				if (inputMatrix[r][c] != 0) {
					// abbiamo il valore definito dall'utente
					if (inputMatrix[r][c] < 1 || inputMatrix[r][c] > 9)
						throw new IllegalArgumentException(
								"Il valore non e' corretto");
					else {
						// assegna
						// il
						// valore
						// inserito
						// dall'utente
						if(nS==0 || nS==3){
							matrix1[r][c] = new boolean[9];
							matrix1[r][c][inputMatrix[r][c] - 1] = true;
						}
						if(nS==1 || nS==3){
							matrix2[r][c] = new boolean[9];
							matrix2[r][c][inputMatrix[r][c] - 1] = true;
						}
						if(nS==2 || nS==3){
							matrix3[r][c] = new boolean[9];
							matrix3[r][c][inputMatrix[r][c] - 1] = true;
						}
					}
				} else {
					if(nS==0 || nS==3){
						matrix1[r][c] = new boolean[] { true, true, true, true,
							true, true, true, true, true };
					}
					if(nS==1 || nS==3){
						matrix2[r][c] = new boolean[] { true, true, true, true,
							true, true, true, true, true };
					}
					if(nS==2 || nS==3){
						matrix3[r][c] = new boolean[] { true, true, true, true,
							true, true, true, true, true };
					}
				}
			}
		}
	}

	/**
	 * Metodo che legge il 
	 * @return cubo con valori sudoku
	 */
	public boolean[][][] getMatrix(int nS) {
		if(nS==0)
			return matrix1;
		if(nS==1)
			return matrix2;
		if(nS==2)
			return matrix3;
		return null;
	}
  
	/**
	 * Metodo che legge 
	 * @return iput dato
	 */
	public int[][] getInput(int i) {
		return input[i];
	}

	
	public void setOver(int i) {
		end[i] = true;
	}

	public void resetOver(int i) {
		end[i] = false;
	}
 
	/**
	 * Metodo che indica se si è alla fine
	 * * @return si/no
	 */
	public boolean isOver(int i) {
		return end[i];
	}
	
	public void addPassi(int i){
		passi[i]++;
		if(gWindow!=null)
			gWindow.addAcValue(i, passi[i]);
	}
	
	public void resetPassi(int i){
		if(gWindow!=null)
			gWindow.addValue(i, passi[i]);
		
		if(passi[i]<min[i]){
			min[i]=(int)passi[i];
		}
		if(passi[i]>max[i]){
			max[i]=passi[i];
		}
		passi[i]=0;
	}
	
	public long getPassi(int i){
		return passi[i];
	}
	
	public int getMin(int i){
		return min[i];
	}
	
	public long getMax(int i){
		return max[i];
	}
	
	public static void setRit(int r){
		rit=r;
	}
	
	public static int getRit(){
		return rit;
	}
	
	public static Object getWait(){
		return wait;
	}
	
	public void closeGraph(){
		gWindow.dispose();
	}
	
	private static boolean forceClose=false;
	public static void closeTest(){
		forceClose=true;
		finito();
		for(int i=0;i<3;i++){
			end[i]=true;
		}
		synchronized (wait) {
			wait.notifyAll();
		}
	}
	
	public boolean isForce(){
		return forceClose;
	}
	
	public void resetForce(){
		forceClose=false;
	}
	
	public static void finito(){
		gWindow.setAlwaysOnTop(false);
	}
	
	private static Color[] coloriSolver = new Color[] { Color.blue, Color.red, new Color(0,205,50) };
	public static Color getColor(int i){
		return coloriSolver[i];
	}
	
	
	public static void setDelay(String t){
		System.out.println(t);
		if(t.equals("Space") || t.equals("Barra spaziatrice")){
			rit=0;
		}
		if(t.equals("1")){
			rit=100;
		}
		if(t.equals("2")){
			rit=200;
		}
		if(t.equals("3")){
			rit=300;
		}
		if(t.equals("4")){
			rit=400;
		}
		if(t.equals("5")){
			rit=500;
		}
		if(t.equals("6")){
			rit=600;
		}
		if(t.equals("7")){
			rit=700;
		}
		if(t.equals("8")){
			rit=800;
		}
		if(t.equals("9")){
			rit=900;
		}
		if(t.equals("0")){
			rit=1000;
		}
		if(t.equals("Invio") || t.equals("Enter")){
			rit=10000;
		}
		
		if(t.equals("Esc") || t.equals("Escape")){
			closeTest();
		}
		else{
			synchronized (wait) {
				wait.notifyAll();
			}
		}
		if(gWindow!=null)
			gWindow.changeRit(rit);
	}

	/**
	 * Metodo per stampare il cubo
	 */
	public void stampaCose() {
		for (int r = 0; r < 9; r++) {
			for (int c = 0; c < 9; c++) {
				int min = 0;
				for (int k = 0; k < 9; k++) {
					if (matrix1[r][c][k]) {
						System.out.print(k + 1 + " ");
						break;
					}
				}
			}
			System.out.println();
		}
	}

	/**
	 * metodo che propaga i vincoli
	 * 
	 * @param cubo_valori
	 *            cubo con valori in ingresso
	 * @param val
	 *            valore assegnato alla cella
	 * @param r
	 *            indice riga cella
	 * @param c
	 *            indice colonna cella
	 * @param nS numero Solver
	 * 
	 * @return vero/falso
	 */

	public boolean applyContstrains(boolean[][][] cubo_valori, int val,
			int r, int c, int nS) {

		// eliminazione valori dalla riga r
		for (int co = 0; co < 9; co++) {
			addPassi(nS);
			if (co != c)
				cubo_valori[r][co][val - 1] = false;
			int i = 0;
			while (i < 9 && !cubo_valori[r][co][i]) {
				addPassi(nS);
				i++;
			}
			if (i == 9)
				return false;
		}

		// eliminazione valori dalla colonna c
		for (int ri = 0; ri < 9; ri++) {
			addPassi(nS);
			if (ri != r)
				cubo_valori[ri][c][val - 1] = false;
			int j = 0;
			while (j < 9 && !cubo_valori[ri][c][j]) {
				addPassi(nS);
				j++;
			}
			if (j == 9)
				return false;
		}

		// eliminazione valori dal quadrato
		int nr_quad = (r / 3) * 3;
		int nc_quad = (c / 3) * 3;
		for (int i = nr_quad; i < nr_quad + 3; i++) {
			for (int j = nc_quad; j < nc_quad + 3; j++) {
				addPassi(nS);
				if (!(i == r && j == c))
					cubo_valori[i][j][val - 1] = false;
				int k = 0;
				while (k < 9 && !cubo_valori[i][j][k]) {
					addPassi(nS);
					k++;
				}
				if (k == 9)
					return false;

			}

		}
		return true;
	}

}